home *** CD-ROM | disk | FTP | other *** search
/ Acorn Risc Technologies StrongARM CD-ROM / Acorn Risc Technologies StrongARM CD-ROM.iso / ftp / documents / appnotes / 276_290 / 280c / Text
Encoding:
Text File  |  1995-06-12  |  81.2 KB  |  1,941 lines

  1. -----------------------------------------------------------------------------
  2. 26th April 1995
  3. -----------------------------------------------------------------------------
  4. Support Group Application Note
  5. Number: 280
  6. Issue:  0.00
  7. Author: IDJ
  8. -----------------------------------------------------------------------------
  9. Writing Toolbox Object Modules
  10. -----------------------------------------------------------------------------
  11. Notes: 
  12.  
  13. -----------------------------------------------------------------------------
  14. Applicable Hardware: All machines running RISC OS 3.10 and later
  15.  
  16. Related Application Notes: 281
  17.  
  18.  
  19. -----------------------------------------------------------------------------
  20. Copyright (C) 1995 Acorn Computers Limited 
  21.  
  22. Every effort has been made to ensure that the information in this leaflet is 
  23. true and correct at the time of printing. However, the products described in
  24. this leaflet are subject to continuous development and improvements and
  25. Acorn Computers Limited reserves the right to change its specifications at
  26. any time. Acorn Computers Limited cannot accept liability for any loss or
  27. damage arising from the use of any information or particulars in this
  28. leaflet. ACORN, ECONET and ARCHIMEDES are trademarks of Acorn Computers
  29. Limited.
  30. -----------------------------------------------------------------------------
  31. Support Group
  32. Acorn Computers Limited
  33. Acorn House
  34. Vision Park
  35. Histon
  36. Cambridge
  37. CB4 4AE                                                  
  38. -----------------------------------------------------------------------------
  39.  
  40. Contents
  41. --------
  42.  
  43. 1  Introduction
  44. 2  Definition of an Object Module
  45. 3  Object IDs and Internal Handles
  46. 4  Registering with the Toolbox as an Object Module
  47. 5  Dealing with Methods on an Object
  48. 6  Handling Wimp Events, Wimp Messages and Toolbox Events
  49. 7  Finalisation
  50. 8  Toolbox Service Calls
  51. 9  Object Class Numbers and Toolbox Event codes
  52. 10 Interfacing with ResEd, ResCreate and ResTest
  53. 11 A Generic Object Module
  54.  
  55. Appendix 1:   Adding a Class Specific Editor to ResEd
  56.  
  57. 1 Introduction
  58. --------------
  59. The User Interface Toolbox has been designed to be extensible to support any
  60. number of Object Classes by the creation of Object Modules which implement
  61. those Classes.  ResEd (the resource file editor supplied with Acorn C/C++)
  62. was also designed so that editors for new Object Templates can be added
  63. without the need to alter the main ResEd binary.
  64.  
  65. This document describes how to write an Object Module, and how to interface
  66. a new editor for the Object Template with the ResEd Shell program.
  67.  
  68.  
  69. 2  Definition of an Object Module
  70. ---------------------------------
  71. Associated with each Object Class, there is a module which implements and
  72. manages that Class.  Each such module is called an Object Module and must
  73. comply with the set of conventions laid down in the following sections.
  74.  
  75. The Toolbox itself knows only about generic Objects, and uses the Object
  76. Modules to implement the details of the Object.  For example when a Window
  77. Object is created using SWI Toolbox_CreateObject, the Toolbox merely creates
  78. a new entry in  its list of Objects for the current task, and returns a
  79. unique ID for that Object; it calls the Window Object Module to actually
  80. create the underlying Window Object from its Object Template description; 
  81. it is the Window Object Module which will call SWI Wimp_CreateWindow to
  82. actually create the real Wimp window.  Similarly when a Window Object is
  83. deleted using SWI Toolbox_DeleteObject, the Toolbox merely removes this
  84. entry from its list of Objects for the current task, and calls the Window
  85. Object Module to actually use SWI Wimp_DeleteWindow to delete the real Wimp
  86. window.
  87.  
  88. An Object Module must deal with the following  (at least):
  89.  
  90.         - registering with the Toolbox as an Object Module supporting a 
  91.           given Object Class
  92.         - dealing with methods on Objects of the given Class
  93.         - dealing with Wimp Events, Wimp Messages and 
  94.           Toolbox Events
  95.         - deregistering with the Toolbox on finalisation
  96.         - dealing with client tasks starting up
  97.  
  98. Typically, an Object Module will register itself with the Toolbox in its
  99. initialisation code using SWI Toolbox_RegisterObjectModule  (see the section
  100. "Registering with the Toolbox as an Object Module").  This tells the Toolbox
  101. how to deal with methods on Objects of the given Class.  When a method is
  102. applied to Objects of the given Class, the module's Class SWI will be called 
  103. (see the section "Dealing with Methods on an Object").  When the Toolbox
  104. itself is initialised it sends round a service call Toolbox_Starting, and
  105. Object Modules should register themselves with the Toolbox (as above) when
  106. they receive this service call.
  107.  
  108. Whenever a new Toolbox task starts up, the Toolbox sends round a service
  109. call Toolbox_TaskBorn to inform Object Modules of this new task's Wimp task
  110. handle.  An Object Module should typically keep a linked list of client
  111. tasks (remembering their task handles), where each task descriptor has a
  112. linked list of the Objects for that task.  Note that when a Toolbox method
  113. is applied to an Object, the task handle of the calling task is passed to
  114. the Object Module thus allowing it to look down its list of task descriptors
  115. to find that task.
  116.  
  117. When a Toolbox task exits, the Toolbox sends round a service call
  118. Toolbox_TaskDied, quoting the task's Wimp task handle.  This allows an
  119. Object Module to delete the task descriptor for that task, and also (more
  120. importantly) to delete any Objects which that task owns.  the Toolbox will
  121. have removed its record of a dying task's Objects, but does not do this via
  122. Toolbox_DeleteObject, so Object Modules must tidy up their per-task data
  123. structures themselves.  In particular, an Object Module should ensure that
  124. all memory associated with the dying task is freed, even if it encounters
  125. errors while cleaning up.
  126.  
  127. When the client application polls the Wimp, the Toolbox's Wimp prefilter and
  128. postfilter are called.  An Object Module can choose to be put on the chain
  129. of Object Modules called in this prefilter by calling SWI
  130. Toolbox_RegisterPreFilter, specifying a SWI entry point  (see the section
  131. "Handling Wimp Events, Wimp Messages and Toolbox Events").  Object Modules
  132. will use the prefilter mechanism to ensure that the client application has
  133. not masked out events which are needed by that Object Module.  An Object
  134. Module can also elect to be called when specific Wimp Events, Wimp Messages
  135. or Toolbox Events are delivered to the client application on exit from SWI
  136. Wimp_Poll  (ie during the Toolbox's postfilter).  This is achieved by
  137. calling SWI Toolbox_RegisterPostFilter (see the section "Handling Wimp
  138. Events, Wimp Messages and Toolbox Events").
  139.  
  140. When an Object Module's finalisation code is entered  (maybe due to RMKill
  141. or because another version of the module has been RMLoaded) it should free
  142. up its allocated memory, and call SWI Toolbox_DeRegisterObjectModule (see
  143. the section "Finalisation") to cancel its registration with the Toolbox. 
  144. Note that an Object Module should refuse to finalise (and return a suitable
  145. error) if it still has active applications running.
  146.  
  147.  
  148. 3  Object IDs and Internal Handles
  149. ----------------------------------
  150. The Toolbox itself maintains a set of data structures associated with each
  151. Object for each client task;  IDs for these Objects are unique within a
  152. task.  Also associated with each Object is its "internal" handle; this is
  153. the value returned by the Object Module when an Object is created.  An
  154. Object Module is passed this "internal" handle whenever a method has been
  155. applied to one of its Objects.
  156.  
  157. Given an Object ID, an Object Module can request its "internal" handle from
  158. the Toolbox, using SWI Toolbox_GetInternalHandle.  In general this should
  159. not be necessary because the Toolbox passes the internal handle to an Object
  160. module in most cases where it is needed.
  161.  
  162. SWI Toolbox_GetInternalHandle
  163.  
  164. Entry:
  165. R0  =  flags
  166. R1  =  Object ID
  167.  
  168. Exit:
  169. R0  =  "internal" handle
  170.  
  171. Usage:
  172. This SWI returns the "internal" handle which was passed back to the Toolbox
  173. by the relevant Object Module when the Object was created.
  174.  
  175.  
  176. 4  Registering with the Toolbox as an Object Module
  177. ---------------------------------------------------
  178. Associated with each Object Class, there is a SWI number which will be
  179. called in order to provide the fundamental methods on Objects of that Class. 
  180. This is referred to as the Class SWI.
  181.  
  182. When an Object Module starts up, it should register itself with the Toolbox,
  183. and declare its Class SWI using SWI Toolbox_RegisterObjectModule.
  184.  
  185. SWI Toolbox_RegisterObjectModule
  186.  
  187. Entry:  
  188. R0  =  flags
  189. R1  =  Object Class Number
  190. R2  =  Class SWI Number
  191. R3  -> filename where module's resources file is held (or 0 for none).
  192.  
  193. Exit:
  194. R1-R9 preserved
  195.   
  196. Usage:
  197. This SWI is called by an Object module to declare that methods on Objects of
  198. the given Class, should be done by calling the specified "Class SWI".
  199.  
  200. The resources held in the file whose name is pointed at by R3 are loaded by
  201. the Toolbox, and will be searched when the client makes Toolbox_CreateObject
  202. calls.  This is primarily used by modules which implement a standard
  203. dialogue, and need to hold a Window template for creating the dialogue box
  204. itself.  For example, the ProgInfo module has a resource file containing two
  205. Window Templates called _ProgInfo1 and _ProgInfo2, which it uses for calls
  206. to Toolbox_CreateObject to create its underlying Window Objects.
  207.  
  208. IMPORTANT NOTE:  In the current implementation, the Class SWI Number and the
  209. Object Class Number must be the same.
  210.  
  211.  
  212. 5  Dealing with Methods on an Object
  213. ------------------------------------
  214. Whenever a method is called on an Object of a type for which an Object
  215. Module has registered itself with the Toolbox, that Object Module's Class
  216. SWI is called.
  217.  
  218. On entry to the Class SWI, registers R0-R4 have the following contents:
  219.  
  220. R0  =  reason code telling which Toolbox method was called (eg 0 means 
  221.        Toolbox_CreateObject)
  222. R1  =  Object ID
  223. R2  = "internal" handle passed back by this Class module when the Object 
  224.        was created (will be 0 for Toolbox_CreateObject)
  225. R3  =  Wimp task handle of client application
  226. R4  -> block containing the client's R0-R9
  227.  
  228.  
  229. IMPORTANT: The Class SWI should only alter the contents of the client's
  230. register block for a call to SWI Toolbox_ObjectMiscOp (ie reason code 6); 
  231. for all other methods, it is the Toolbox which fills in these return
  232. registers; there is no need to set the client's R0 to point to an error
  233. block, in case of an error, since this will be done by the Toolbox, from the
  234. error block passed back by the Class SWI.
  235.  
  236. Register usage in the client's block is as documented in the User Interface
  237. Toolbox Manual supplied with Acorn C/C++.
  238.  
  239. Note that in the list given below, reason code 2 is deliberately undefined.
  240.  
  241. In order to implement its methods, a Class SWI should have the functionality
  242. shown below.  Note that any references to registers refer to the register
  243. block passed to the Object Module by the Toolbox NOT the user registers
  244. (which are held in the block pointed at by the Toolbox's R4), unless
  245. otherwise stated.
  246.  
  247. Reason Toolbox_CreateObject (0)
  248.  
  249. Exit:
  250. R0 = "internal" handle of created Object.
  251.  
  252. Usage:
  253. On entry to this method, the user's R1 register will contain a pointer to a
  254. template description (not its name).  If the client specified a named
  255. template to SWI Toolbox_CreateObject, then before calling the Class SWI, the
  256. Toolbox replaces this with a real pointer to the template itself. 
  257.  
  258. The Toolbox checks to see if the Object is a shared one which already
  259. exists, in which case it does not call the Class SWI, but just returns the
  260. appropriate Object ID, and increments the reference count.
  261.  
  262. This method should create a new instance of an Object of its class, and
  263. return an "internal" handle for the Object to the Toolbox via R0 (the
  264. Toolbox's R0 that is NOT the client's R0).  This "internal" handle is the
  265. one which will be passed back to the Object Module when the client uses
  266. other Toolbox methods on the Object.
  267.  
  268. If the Object description contains references to other Object templates,
  269. then this method should call Toolbox_CreateObject for these, and record the
  270. returned IDs.
  271.  
  272.  
  273. Reason Toolbox_DeleteObject (1)
  274.  
  275. Exit:
  276. R1-R9 preserved
  277.  
  278. Usage:
  279. This SWI should remove the data structures associated with the Object with
  280. the given "internal" handle.  If this Object contains IDs for other Objects,
  281. then this SWI should call SWI Toolbox_DeleteObject for those Objects (unless
  282. bit 0 is set). 
  283.  
  284. The Toolbox itself deals with reference counts for Shared Objects, so this
  285. method is only called when an Object's reference count reaches 0.
  286.  
  287.  
  288. Reason Toolbox_ShowObject (3)
  289.  
  290. Exit:
  291. If bit 1 of the flags word was set, then R0 should contain a value suitable 
  292. for use as a Wimp Menu pointer.
  293. R1-R9 preserved
  294.  
  295. Usage:
  296. This method should display the given Object on the screen.  Exact semantics 
  297. will vary for different Object classes.
  298.  
  299.  
  300. Reason Toolbox_HideObject (4)
  301.  
  302. Exit:
  303. R1-R9 preserved
  304.  
  305. Usage:
  306. This method should remove a previously displayed Object from the screen.  
  307. Exact semantics will vary for different Object classes.
  308.   
  309.  
  310. Reason Toolbox_GetObjectState (5)
  311.  
  312. Exit:
  313. R0  =  Object state
  314.  
  315. Usage:
  316. This SWI should fill in R0 with state information for the given Object.
  317.  
  318.  
  319. Reason Toolbox_MiscOp (6)
  320.  
  321. Exit:
  322. R1-R9 preserved.
  323. The user register block (pointed at by R4) should be filled in as 
  324. appropriate for this particular method.
  325.  
  326. Usage:
  327. This SWI is used to implement all of the Toolbox_MiscOp methods which 
  328. are Object-specific.
  329.  
  330.  
  331. 6  Handling Wimp Events, Wimp Messages and Toolbox Events
  332. ---------------------------------------------------------
  333. The Toolbox registers a single PostFilter and a single PreFilter with the
  334. Wimp.  Object Modules should register interest in Wimp Events, Wimp Messages
  335. and Toolbox Events with the Toolbox, so that their appropriate handler SWIs
  336. can be called in the PostFilter.  This is done using SWI
  337. Toolbox_RegisterPostFilter as documented below.  An Object Module can choose
  338. to be called in the PreFilter by using SWI Toolbox_RegisterPreFilter.  This
  339. is useful for modifying the mask passed to SWI Wimp_Poll in case the client
  340. application has not enabled a particular Wimp event which is needed by this
  341. Object Module.
  342.  
  343.  
  344. SWI Toolbox_RegisterPostFilter      
  345.  
  346. Entry:
  347. R0  =  flags
  348. bit 0 set means no longer interested in being called by post-filter, for the 
  349.        list of pairs pointed at by R4, and the given SWI number, and the 
  350.        given R2 value.
  351. R1  =  SWI number to be called by filter
  352. R2  =  one-word value to be passed to the postfilter SWI in R2
  353. R3  =  filter type
  354.                 1 => Wimp Events
  355.                 2 => Wimp Messages
  356.                 3 => Toolbox Events
  357. R4  =  -> list of pairs of either:
  358.                 Wimp Event code,  Object Class 
  359.                 Wimp Message number, Object Class  or
  360.                 Toolbox Event code,  Object Class
  361.                 depending on the value of R3.  
  362.                         The list is terminated by two words containing -1.
  363.  
  364. Exit:
  365. R1-R9 preserved
  366.  
  367. Usage:
  368. This SWI is used to get Wimp Events, Wimp Messages or Toolbox Events
  369. delivered to an Object Module.  It is used by that module to vet events
  370. before they are passed to the client application.
  371.  
  372. If an Object Module registers for a Wimp Message, then that message is added
  373. to those received by the client using SWI Wimp_AddMessages, unless the
  374. client was receiving all Wimp Messages anyway.  NOTE: an Object Module
  375. should not call SWI Wimp_AddMessages itself.
  376.  
  377. Modules which have registered themselves to receive a particular event are
  378. called when that event occurs, when the Object ID field in the application's
  379. poll block is one for an Object of the specified Class (an Object Class
  380. value of 0 means that the Object Module is interested in events on
  381. underlying Wimp objects, and an Object Class value of -1 means that the
  382. Object Module is interested in events on Objects of ALL classes).  For
  383. example, the Window Module registers interest in all Wimp Events which can
  384. happen on a Window, in order to fill in the Object ID of that Window in the
  385. client's ID block;  this is done by registering for those Events on
  386. underlying Wimp objects using the special value 0, ie:
  387.  
  388. EventInterest   events_of_interest[] = 
  389.                 {{ Wimp_ERedrawWindow          , 0},
  390.                  {Wimp_EOpenWindow             , 0},
  391.                  {Wimp_ECloseWindow            , 0},
  392.                  {Wimp_EPointerLeavingWindow   , 0},
  393.                  {Wimp_EPointerEnteringWindow  , 0},
  394.                  {Wimp_EMouseClick             , 0},
  395.                  {Wimp_EKeyPressed             , 0},
  396.                  {Wimp_EUserDrag               , 0},
  397.                  {Wimp_EScrollRequest          , 0},
  398.                  {Wimp_ELoseCaret              , 0},
  399.                  {Wimp_EGainCaret              , 0},
  400.                  {Wimp_EUserMessage            , 0},
  401.                  {Wimp_EUserMessageRecorded    , 0},
  402.                  {- 1                          , -1}
  403.                 };
  404.  
  405. It also registers interest for Toolbox Events on Objects of the Window Class
  406. and Menu Class in order to implement composite Gadgets  (eg the code to deal
  407. with Number Ranges needs to receive Adjuster_Clicked Events, and the code to
  408. deal with String Sets needs to receive Menu_Selection Events), so it uses
  409. the following block:
  410.  
  411. EventInterest   toolbox_events_of_interest[] = 
  412.       {{Window_AboutToBeShown       , Window_ObjectClass}, 
  413.        {Adjuster_Clicked            , Window_ObjectClass}, 
  414.        {Slider_ValueChanged         , Window_ObjectClass}, 
  415.        {WritableField_ValueChanged  , Window_ObjectClass}, 
  416.        {PopUp_AboutToBeShown        , Window_ObjectClass},
  417.        {StringSet_AboutToBeShown    , Window_ObjectClass},
  418.        {Menu_Selection              , Menu_ObjectClass},
  419.        {- 1                         , -1}
  420.       };
  421.  
  422.  
  423. The SWI whose number is passed in R1 to SWI Toolbox_RegisterPostFilter
  424. should have the following behaviour:
  425.  
  426. Entry:
  427. R0  =  Wimp Event reason code returned from Wimp_Poll
  428. R1  =  pointer to event block as returned from SWI Wimp_Poll
  429. R2  =  value passed in R2 to SWI Toolbox_RegisterPostFilter. 
  430. R3  -> 6-word "ID block" as passed to Toolbox_Initialise by the client.
  431.  
  432. Exit:
  433. R0 contains the Wimp Event reason code returned from Wimp_Poll.  In the case
  434. of a Toolbox Event, this will be 0x200, and for a Wimp Message it will be
  435. the standard values User_Message (0x11) or User_Message_Recorded (0x12).  In
  436. the case of a Toolbox Event, the event details are held in the event block
  437. passed in R1.
  438.  
  439. If the Wimp Event, Wimp Message or Toolbox Event is for an Object maintained
  440. by this Object module and it wishes to indicate which Object it is, this is
  441. done by filling in the "self" field in the client's "ID Block".  If the
  442. Object module has updated the "ID block" then it MUST return a non-zero
  443. value in R0, to indicate that it has "claimed" the event, otherwise it
  444. should set R0 to zero.  The Toolbox will deal with filling in the Parent and
  445. Ancestor fields in the client's "ID Block", so the Object Module should not
  446. alter these fields.
  447.                            
  448. Only one module can claim a particular event on an Object of a particular
  449. type.  If more than one claim is attempted, then an error is raised.  Note,
  450. however, that after an event is claimed, that event is still passed on to
  451. other modules interested in the event.
  452.  
  453. The Toolbox will continue to repeatedly pass the event to Object Modules
  454. whose criteria passed to SWI Toolbox_RegisterPostFilter are met, and as long
  455. as one of these Modules indicates that it has updated the ID block.  Great
  456. care must be taken here by Object Modules to avoid an infinite loop.
  457.                            
  458. No changes can be made to the event block itself.  If the module wishes to
  459. cause further events to happen this should be done using Wimp_SendMessage or
  460. by raising a Toolbox Event via SWI  Toolbox_RaiseToolboxEvent.  Before the
  461. Toolbox returns to the client, all original register contents are restored,
  462. and the Parent and Ancestor fields of the "ID Block" are filled in by the
  463. Toolbox.
  464.  
  465. Example:
  466.  
  467. The Iconbar module contains the following code:
  468. EventInterest   messages_of_interest[] =
  469.                 {{ Wimp_MHelpRequest  , 0},
  470.                  {- 1                 ,-1}
  471.                 };
  472.  
  473. EventInterest   events_of_interest[] = 
  474.                 {{ Wimp_EMouseClick   , 0},
  475.                  {- 1                 ,-1}
  476.                 };
  477.  
  478. EventInterest   toolbox_events_of_interest[] = 
  479.                 {{ Iconbar_SelectAboutToBeShown,  Iconbar_ObjectClass},
  480.                  { Iconbar_AdjustAboutTobeShown , Iconbar_ObjectClass},
  481.                  {- 1                           ,  -1}
  482.                 };
  483.  
  484. These data blocks are passed to SWI Toolbox_RegisterPostFilter and mean that
  485. the Iconbar module is interested in being called in the PostFilter when a
  486. Help Request message is received on any Wimp object, when a Mouse Click
  487. event is received on any Wimp object, and when the
  488. Iconbar_SelectAboutToBeShown and Iconbar_AdjustAboutToBeShown Toolbox Events
  489. are received on Objects of the Iconbar Object Class.
  490.  
  491. Note: The Iconbar Module registers interest in the AboutToBeShown events to
  492. ensure that the client is delivered this event BEFORE the attached Object is
  493. shown.  It does this by noting that the AboutToBeShown event has been
  494. delivered (in the PostFilter) to the client, and then actually showing the
  495. attached Object on the next call to the Iconbar Module's PreFilter.  In the
  496. PreFilter we are thus assured that the AboutToBeShown event has been
  497. delivered, and that the client has called SWI Wimp_Poll since delivery of
  498. the event.
  499.  
  500. For efficiency reasons, we realise that these events can only happen for an
  501. Iconbar Object, when that Object is actually showing on the Iconbar, so the
  502. Iconbar Object Module registers interest in the above events in its function
  503. which deals with showing an Iconbar Object, ie:
  504.  
  505.     regs.r[0] = 0;
  506.     regs.r[1] = Iconbar_PostFilter;
  507.     regs.r[2] = (int)iconbar_icon;
  508.     regs.r[3] = Toolbox_RegisterPostFilter_WimpEvent;
  509.     regs.r[4] = (int)events_of_interest;
  510.  
  511.     if ((e = _kernel_swi (Toolbox_RegisterPostFilter, ®s, ®s)) != NULL)
  512.         return e;
  513.  
  514.     regs.r[0] = 0;
  515.     regs.r[1] = Iconbar_PostFilter;
  516.     regs.r[2] = (int)iconbar_icon;
  517.     regs.r[3] = Toolbox_RegisterPostFilter_WimpMessage;
  518.     regs.r[4] = (int)messages_of_interest;
  519.  
  520.     if ((e = _kernel_swi (Toolbox_RegisterPostFilter, ®s, ®s)) != NULL)
  521.         return e;
  522.  
  523.     regs.r[0] = 0;
  524.     regs.r[1] = Iconbar_PostFilter;
  525.     regs.r[2] = (int)iconbar_icon;
  526.     regs.r[3] = Toolbox_RegisterPostFilter_ToolboxEvent;
  527.     regs.r[4] = (int)toolbox_events_of_interest;
  528.  
  529.     if ((e = _kernel_swi (Toolbox_RegisterPostFilter, ®s, ®s)) != NULL)
  530.         return e;
  531.  
  532. Then in the function which deals with hiding an Iconbar Object, the
  533. PostFilters are deregistered:
  534.  
  535.     regs.r[0] = Toolbox_RegisterPostFilter_Remove;
  536.     regs.r[1] = Iconbar_PostFilter;
  537.     regs.r[2] = (int)iconbar_icon;
  538.     regs.r[3] = Toolbox_RegisterPostFilter_WimpEvent;
  539.     regs.r[4] = (int)events_of_interest;
  540.  
  541.     if ((e = _kernel_swi (Toolbox_RegisterPostFilter, ®s, ®s)) != NULL)
  542.         return e;
  543.  
  544.     regs.r[0] = Toolbox_RegisterPostFilter_Remove;
  545.     regs.r[1] = Iconbar_PostFilter;
  546.     regs.r[2] = (int)iconbar_icon;
  547.     regs.r[3] = Toolbox_RegisterPostFilter_WimpMessage;
  548.     regs.r[4] = (int)messages_of_interest;
  549.  
  550.     if ((e = _kernel_swi (Toolbox_RegisterPostFilter, ®s, ®s)) != NULL)
  551.         return e;
  552.  
  553.     regs.r[0] = Toolbox_RegisterPostFilter_Remove;
  554.     regs.r[1] = Iconbar_PostFilter;
  555.     regs.r[2] = (int)iconbar_icon;
  556.     regs.r[3] = Toolbox_RegisterPostFilter_ToolboxEvent;
  557.     regs.r[4] = (int)toolbox_events_of_interest;
  558.  
  559.     if ((e = _kernel_swi (Toolbox_RegisterPostFilter, ®s, ®s)) != NULL)
  560.         return e;
  561.  
  562. In the registration calls, the SWI Iconbar_PostFilter will be called when
  563. any of the specified events happen on Objects of the specified classes.  The
  564. value passed in R2 to SWI Iconbar_PostFilter is actually the internal handle
  565. of the Iconbar Object; in the Iconbar Module we chose to have one handler
  566. registered for each Object since in general, each task will not have a great
  567. number of Iconbar Objects showing at any one time.  When Iconbar_PostFilter
  568. is called it does the following check to see if the event is actually for
  569. this Iconbar Object or not; if not it just returns without dealing with the
  570. event:
  571.  
  572. extern _kernel_oserror *events_postfilter (_kernel_swi_regs *r)
  573. {
  574.     /*
  575.      * called from the main Toolbox postfilter, when an event happens which
  576.      * this module has expressed an interest in.
  577.      * R0 = Wimp event reason code
  578.      * R1 ->client's Wimp event block
  579.      * R2 = pointer to icon object
  580.      * R3 ->6-word "ID block" as passed to Toolbox_Initialise
  581.      *
  582.      */
  583.  
  584.     /*
  585.      * This function gets a pointer to an Iconbar Object in
  586.      * R2 (since this was the value passed to Toolbox_RegisterPostFilter).
  587.      * If the event is dealt with by this module (ie ID block gets updated).
  588.      * then set R0 to non-null before return.
  589.      */
  590.  
  591.     int              event_code =  r->r[0];
  592.     WimpPollBlock   *block      = (WimpPollBlock *)r->r[1];
  593.     IdBlock         *id_block   = (IdBlock *)r->r[3];
  594.     _kernel_oserror *e          = NULL;
  595.     Object          *icon       = (Object *)r->r[2];
  596.  
  597.     r->r[0] = 0;   /* default is "we haven't handled the event" */
  598.  
  599.     /*
  600.      * for safety we return if NULL handle passed in 
  601.      */
  602.  
  603.     if (icon == NULL)
  604.         return NULL;
  605.  
  606.     /*
  607.      * deal with the event 
  608.      */
  609.  
  610.     switch (event_code)
  611.     {
  612.         case Wimp_EMouseClick: 
  613.             if (block->mouse_click.window_handle != WimpWindow_Iconbar)
  614.                break;
  615.  
  616.             /*
  617.              * first find if it's one of our icons.  If so process the mouse click.
  618.              */
  619.  
  620.             if (icon->wimp_icon_handle == block->mouse_click.icon_handle)
  621.                 e = events__button_click (icon, block, id_block, r);
  622.  
  623.             break;
  624.  
  625.        etc............
  626.  
  627. In the events__button_click function we actually deal with the mouse click,
  628. and update the ID Block with the Toolbox Object ID of this Iconbar Object,
  629. as shown below:
  630.  
  631. static _kernel_oserror *events__button_click (Object *icon, 
  632.                                               WimpPollBlock *block, 
  633.                                               IdBlock *id_block, 
  634.                                               _kernel_swi_regs *r)
  635. {
  636.     _kernel_oserror *e = NULL;
  637.  
  638.     if (block->mouse_click.buttons & Wimp_MouseButtonMenu)
  639.     {
  640.         /*
  641.          * if iconbar object has attached menu, then show it.
  642.          */
  643.  
  644.         if (icon->menu != NULL) 
  645.             if ((e = events__show_menu (icon, block->mouse_click.x, block->mouse_click.y))
  646.                  != NULL)
  647.               return e;
  648.  
  649.         /*
  650.          * update the id block to say which object the original click was
  651.          * on, so return non-zero R0 to show this.
  652.          */
  653.  
  654.         id_block->self_id = icon->id; /* we have remembered the object id here */
  655.         id_block->self_component = NULL_ComponentId;
  656.  
  657.         r->r[0] = 1;  
  658.     }
  659.     else if (block->mouse_click.buttons & 
  660.             (Wimp_MouseButtonSelect | Wimp_MouseButtonAdjust))
  661.     {
  662.         IconbarClickedEvent clicked_event ;
  663.         _kernel_swi_regs    regs;
  664.  
  665.         if (((icon->flags & Iconbar_GenerateSelectClickedEvent) &&
  666.              (block->mouse_click.buttons & wimp_SELECT_BUTTON)) 
  667.               ||
  668.              ((icon->flags & Iconbar_GenerateAdjustClickedEvent) && 
  669.              (block->mouse_click.buttons & wimp_ADJUST_BUTTON))
  670.             )
  671.         {
  672.             /*
  673.              * raise Toolbox Event to client (default is Iconbar_Clicked)
  674.              */
  675.  
  676.             clicked_event.hdr.size = sizeof(IconbarClickedEvent);
  677.             clicked_event.hdr.event_code = Iconbar_Clicked;
  678.  
  679.             clicked_event.hdr.flags = block->mouse_click.buttons & 0x0f;
  680.  
  681.             if (icon->select_event != 0 && 
  682.                (block->mouse_click.buttons & wimp_SELECT_BUTTON))
  683.                clicked_event.hdr.event_code = icon->select_event;
  684.             else if (icon->adjust_event != 0 && 
  685.                (block->mouse_click.buttons & wimp_ADJUST_BUTTON))
  686.                clicked_event.hdr.event_code = icon->adjust_event;
  687.  
  688.             regs.r[0] = 0;
  689.             regs.r[1] = (int)icon->id;     /* object id of this iconbar icon */
  690.             regs.r[2] = NULL_ComponentId;  /* no component id */
  691.             regs.r[3] = (int)&clicked_event;
  692.  
  693.             if ((e = _kernel_swi (Toolbox_RaiseToolboxEvent, ®s, ®s)) != NULL)
  694.                 return e;
  695.         }
  696.           
  697.  
  698.         /*
  699.          * if there is an Object specified to be shown on this click, either
  700.          * raise a Toolbox event to get it shown, or show it immediately
  701.          * depending on flags settings for iconbar Object
  702.          */
  703.  
  704.         if ((block->mouse_click.buttons & wimp_SELECT_BUTTON) && 
  705.             icon->select_show != NULL)
  706.         {
  707.             if (icon->flags & Iconbar_GenerateSelectAboutToBeShown)
  708.                 e = events__raise_about_to_be_shown (icon, 
  709.                                                      icon->select_show, 
  710.                                                      Iconbar_SelectAboutToBeShown);
  711.             else
  712.                 e = events__show_attached_object (icon, Iconbar_SelectAboutToBeShown);
  713.         }
  714.         else if ((block->mouse_click.buttons & wimp_ADJUST_BUTTON) && 
  715.                  icon->adjust_show != NULL)
  716.         {
  717.             if (icon->flags & Iconbar_GenerateAdjustAboutToBeShown)
  718.                 e = events__raise_about_to_be_shown (icon, 
  719.                                                      icon->adjust_show, 
  720.                                                      Iconbar_AdjustAboutToBeShown);
  721.             else
  722.                 e = events__show_attached_object (icon, Iconbar_AdjustAboutToBeShown);
  723.         }
  724.  
  725.         if (e != NULL)
  726.             return e;
  727.  
  728.         /*
  729.          * update the id block to say which object the original click was
  730.          * on, so return non-zero R0 to show this
  731.          */
  732.  
  733.         id_block->self_id = icon->id;
  734.         id_block->self_component = NULL_ComponentId;
  735.  
  736.         r->r[0] = 1;  
  737.     }
  738.  
  739.     return NULL;
  740. }
  741.  
  742.  
  743. A different approach was taken in the Window Module, since many Windows may
  744. be created and shown at any one time; in the Window Module, there is a
  745. single PostFilter registered which scans its linked list of Windows whenever
  746. an event is delivered to see which Window the event is for.  Note that the
  747. calling of an Object Module's PostFilter is via a SWI, so this decision was
  748. taken for efficiency reasons.
  749.  
  750.  
  751. SWI Toolbox_RegisterPreFilter
  752.  
  753. Entry:
  754. R0  =  flags
  755. bit 0 set means no longer interested in being called by pre-filter, for the 
  756. given value in R2.
  757. R1  =  SWI number to be called by filter
  758. R2  =  one-word value to be passed to the SWI (in R2).
  759.  
  760. Exit:
  761. R1-R9 preserved.
  762.  
  763. Usage:
  764. This SWI is used indicate that a particular SWI is to be called before the
  765. Toolbox PreFilter allows SWI Wimp_Poll to continue.
  766.  
  767. The given SWI is called with register contents as they will be when
  768. Wimp_Poll is called.  The SWI can enable any Wimp events which it needs, by
  769. zero-ing appropriate bits in R0 (the Wimp_Poll mask).  R2 is set to the
  770. value passed in R2 to Toolbox_RegisterPreFilter.  Note that the value of R0
  771. on return from the given SWI will be passed on to the next SWI in the chain,
  772. and will finally be passed to Wimp_Poll.  
  773.  
  774. The purpose of this SWI is to allow Object Modules to be informed when the
  775. application calls SWI Wimp_Poll.  It may be used to free up memory which is
  776. only needed between calls to SWI Wimp_Poll, or to set internal state
  777. appropriately.
  778.  
  779. IMPORTANT NOTE:  if an Object Module enables a particular Wimp event which
  780. the client was not expecting, then if this event happens, it is delivered to
  781. all postfilters, but is NOT passed back to the client.  This is important
  782. since the client may have problems caused by receiving an event it thinks it
  783. masked out!
  784.  
  785.  
  786. 7  Finalisation
  787. ---------------
  788. During an Object module's finalisation code, it should do the following:
  789.  
  790.         -  refuse to finalise if it has tasks active, otherwise:
  791.         -  close its messages file
  792.         -  deregister its messages file from ResourceFS
  793.         -  deregister its resources file from ResourceFS (if it has one)
  794.         -  deregister itself from the Toolbox using 
  795.            SWI Toolbox_DeRegisterObjectModule
  796.         -  free up all its allocated memory.    
  797.  
  798. SWI Toolbox_DeRegisterObjectModule      
  799.  
  800. Entry:
  801. R0  =  flags
  802. R1  =  Object Class
  803.  
  804. Exit:
  805. R1-R9 preserved
  806.   
  807. Usage:
  808. This SWI deregisters a previously registered Object module.
  809.  
  810.  
  811.  
  812. 8  Toolbox Service Calls
  813.  
  814. The Toolbox issues service calls to keep Object Class modules informed of
  815. the state of the system.  All such modules should listen for these service
  816. calls and take appropriate action.
  817.  
  818. Toolbox_Starting (0x44ec1)
  819.  
  820. Entry:
  821. R1  =  0x44ec1 (Toolbox_Starting)
  822.  
  823. Exit:
  824. Do not claim.
  825.  
  826. Usage:
  827. This service call is passed round when the Toolbox is initialised; it allows
  828. Toolbox object modules to call SWI Toolbox_RegisterObjectModule.
  829.  
  830.  
  831. Toolbox_TaskBorn (0x44ec2)
  832.  
  833. Entry:
  834. R0  =  Wimp Task handle of newly created task.
  835. R1  =  0x44ec2 (Toolbox_TaskBorn)
  836.  
  837. Exit:
  838. Module should have noted task's handle.
  839. Do not claim.
  840.  
  841. Usage:
  842. This service call is passed round after the Toolbox has called
  843. Wimp_Initialise on behalf of the client application.  It can be used by
  844. Object modules to create a new data structure for a client task.
  845.  
  846. It is also passed round when Toolbox_RegisterObjectModule is called, for
  847. each task which the Toolbox currently knows about.
  848.  
  849.  
  850. Toolbox_TaskDied (0x44ec3)
  851.  
  852. Entry:
  853. R0  =  Wimp Task handle of dead task.
  854. R1  =  0x44ec3 (Toolbox_TaskDied).
  855.  
  856. Exit:
  857. Module should have deleted its per-task info.
  858. Do not claim.
  859.  
  860. Usage:
  861. This service call is passed round when the Wimp_CloseDown service call is
  862. received for a Toolbox application.
  863.  
  864.  
  865.  
  866.  
  867. 9  Object Class Numbers and Toolbox Event Codes
  868.  
  869. Each Object Class has its own Class Number.  These numbers are centrally
  870. allocated by Acorn;  in fact a Class Number is the Class SWI of the Object
  871. Module which implements Objects of that Class.  For example the Iconbar
  872. Module has a SWI chunk starting at 0x82900, and so defines the following
  873. SWIs:
  874.  
  875. #define Iconbar_SWIChunkBase    0x82900
  876. #define Iconbar_ObjectClass     Iconbar_SWIChunkBase
  877. #define Iconbar_ClassSWI        (Iconbar_SWIChunkBase + 0)
  878. #define Iconbar_PostFilter      (Iconbar_SWIChunkBase + 1)
  879. #define Iconbar_PreFilter       (Iconbar_SWIChunkBase + 2) 
  880.  
  881. Iconbar_ClassSWI is the SWI which will be called for all methods on Objects
  882. of the Iconbar Class.  Iconbar_PostFilter and Iconbar_PreFilter are the two
  883. SWIs which wil be registered with the Toolbox to be called during the
  884. Toolbox's PostFilter and PreFilter respectively.
  885.  
  886. Note that a single Object Module may implement more than one Class, by
  887. registering more than one Class SWI from its chunk with the Toolbox, for
  888. example the DCS Module implements both the DCS and Quit objects by
  889. specifying the following SWIs:
  890.  
  891. #define DCS_SWIChunkBase    0x82a80
  892. #define DCS_ObjectClass     DCS_SWIChunkBase
  893. #define DCS_ClassSWI        (DCS_SWIChunkBase + 0)
  894. #define DCS_PostFilter      (DCS_SWIChunkBase + 1)
  895. #define DCS_PreFilter       (DCS_SWIChunkBase + 2)
  896.  
  897.  
  898. #define Quit_SWIChunkBase    0x82a90                 /* &10 + DCSSWIChunk */
  899. #define Quit_ObjectClass     Quit_SWIChunkBase
  900. #define Quit_ClassSWI        (Quit_SWIChunkBase + 0)
  901. #define Quit_PostFilter      (Quit_SWIChunkBase + 1)
  902. #define Quit_PreFilter       (Quit_SWIChunkBase + 2)
  903.  
  904. Toolbox Events should also be based on the Class Number.  For example the
  905. Iconbar Module defines the following Toolbox Events:
  906.  
  907. #define Iconbar_Clicked              (Iconbar_SWIChunkBase + 0)
  908. #define Iconbar_SelectAboutToBeShown (Iconbar_SWIChunkBase + 1)
  909. #define Iconbar_AdjustAboutToBeShown (Iconbar_SWIChunkBase + 2)
  910.  
  911. Error numbers will also be allocated at the same time as the Class Number.
  912.  
  913. In order to be allocated a Class number you will need to supply:
  914.         - details of the Object's Template format
  915.         - the API used for Toolbox_MiscOp methods for your Object
  916.         - the API for any extra SWIs which the Object Module implements
  917.         - the Object Module binary
  918.  
  919. During development you can use one of the available User SWIs as your Class
  920. Number.
  921.  
  922. The IPR for an Object Module resides with its author, but we encourage free
  923. sharing of such Object Modules to ease application development.
  924.  
  925.  
  926. 10 Interfacing with ResEd, ResCreate and ResTest
  927. ------------------------------------------------
  928. ResEd
  929. -----
  930. From version 0.33 onwards, when ResEd is given a template for an Object
  931. Class for which it does not have a registered Class Specific Edtior (CSE -
  932. see Appendix 1 for more details), it displays a generic Object editing
  933. dialogue box which allows the editing of fields of the Object Template using
  934. word offsets from the beginning of the Object's body.  The Object Template's
  935. Class and name will appear in the title bar of the dialogue box used to edit
  936. that Template. 
  937.  
  938. If a CSE is required which gives a more WYSIWYG style of editing, then one
  939. can be written by following the protocols laid down in Appendix 1, however
  940. in most cases this should not prove necessary.
  941.  
  942. Note that ResEd 0.28 (released with Acorn C/C++) will fault Templates of
  943. unknown Object Class.  Note also that in future versions of ResEd, we intend
  944. to make editing of Object Templates table-driven, thus making the "word
  945. offset" approach described above more user-friendly.
  946.  
  947. It is conventional to use names which start with an underscore for Object
  948. Templates which are used by an Object Module (eg the SaveAs module has
  949. Window Objects called "_SaveAs1" and "_SaveAs2).  Normally !ResEd will fault
  950. Template names which do not start with a letter;  by changing the !ResEd
  951. !Run file to pass the "-private" flag on the command line to !ResEd's
  952. !RunImage, underscores are permitted, ie:
  953.  
  954. Run <ResEd$Dir>.!RunImage %*0 -private
  955.  
  956.  
  957. ResCreate
  958. ---------
  959. ResEd is purely an editor of Object Templates and cannot be used to create
  960. new Templates;  the palette of Object Templates is just a read-only resource
  961. file which is created by merging all files named 'Palette' found in its CSE
  962. directories.
  963.  
  964. ResCreate is an application which allows the user to create a "blank" Object
  965. Template.  Such a Template will have null StringReferences and MsgReferences
  966. (see the Resource File Format section of the Acorn C/C++ User Interface
  967. Toolbox Manual).  This will allow ResEd to be used to edit the Template once
  968. it has been created.  Typically, a creator of a new Object Module will use
  969. this bootstrap mechanism to add knowledge of new Object Template prototypes
  970. to ResEd.  This can be done as follows:
  971.  
  972. 1.  Use ResCreate to create a blank Object Template in a Resource File.
  973.  
  974. 2.  Load this file into ResEd, and set up a suitable 'prototype' Object
  975.     Template, saving this back to the Resource File you have just created.
  976.  
  977. 3.  Merge this Resource File into the ResEd !Misc.Palette file.
  978.  
  979. 4.  Add a line to ResEd's !Misc.!Config file for the new Object Template of
  980.     the form: 
  981.  
  982.       <class number>,<template name>,<sprite name>
  983.               
  984.     where sprite name is the name of a sprite to use in ResEd's prototype 
  985.     window.
  986.  
  987. 5.  Create a sprite suitable for this Template and merge it into ResEd's
  988.     !Misc.!Icons and !Misc.!Icons22 sprite files.  The sprite should be 
  989.     called "obj_<name>" following the convention used for existing Object 
  990.     Classes.
  991.  
  992. ResTest
  993. -------
  994. ResTest can display Toolbox Events for new Object Classes by modifying its
  995. Standard and TBlockMess files.  This process is explained in Application
  996. Note 281 (Writing Toolbox Gadgets) in the section "Modifying !ResTest".
  997.  
  998.  
  999.  
  1000. 11 A Generic Object Module
  1001. --------------------------
  1002. Included with this Application Note is a floppy disc containing an example
  1003. "Generic" Object Module which doesn't actually implement a new Object Class,
  1004. but is the skeleton for such a Module.  It deals with initialisation,
  1005. service call handling, SWI dispatching, event handling, task handling,
  1006. registering with Toolbox, resource file handling, and message file handling.
  1007.  
  1008. The example has a makefile for use when building it.  Also on the disc is a
  1009. program called ResGen (in the library directory) which you should copy onto
  1010. your Run$Path.  This program creates an AOF file given an arbitrary input
  1011. file, containing an AOF Area and a function to call by which to reference
  1012. that area.  The return value of this function can then be used to register a
  1013. file with ResourceFS.  The Generic Object Module contains an empty Resource
  1014. File into which an Object Module which uses underlying Objects could place
  1015. its Templates.  For example the SaveAs Module uses a Resource File to store
  1016. its underlying Window Templates.  Many Object Modules will not need an
  1017. embedded Resource File (eg Iconbar, Menu etc), so this can be removed from
  1018. such Modules if they are based on Generic.
  1019.  
  1020. The code for Generic is supplied "as is" and no guarantees are given as to
  1021. its correctness, it is purely there to serve as supporting material for this
  1022. text.
  1023.  
  1024. Note: the Object Modules which were released with Acorn C/C++ use a module
  1025. called TinyStubs to reduce their size by sharing a single copy of the
  1026. "Stubs" object file, and sharing library static data.  This requires a
  1027. special version of the linker, and may be made available to developers at a
  1028. later date.
  1029.  
  1030.  
  1031. Appendix 1:   Adding a Class Specific Editor to ResEd
  1032. -----------------------------------------------------
  1033. The ResEd shell provides facilities for creating, copying and moving
  1034. objects, but does not directly provide facilities for displaying and
  1035. altering the class-specific data attached to objects.  This work is
  1036. delegated to a number of Class Specific Editors (CSEs).  A CSE is a small
  1037. and specialised WIMP application that provides editing operations
  1038. appropriate to one or more ToolBox object classes.  This architecture has
  1039. several advantages over the simpler approach of having one big program: each
  1040. program is manageable in terms of size and complexity; the programs can be
  1041. loaded incrementally; and new CSEs can be added later as new classes become
  1042. available.
  1043.  
  1044. ResEd communicates with its CSEs by means of a simple message protocol,
  1045. described fully later in this section.  As far as the user is concerned, the
  1046. separation between the ResEd shell and the various CSEs is not apparent;
  1047. CSEs are started automatically as required, the intention being to make CSEs
  1048. look like windows and dialogue boxes of the main ResEd application.  As
  1049. such, CSEs have certain differences from normal WIMP applications:-
  1050.  
  1051.         - Started automatically by ResEd
  1052.         - No icon-bar icon
  1053.         - No explicit loading and saving of data
  1054.  
  1055. When the user double-clicks on an object's icon in the document display,
  1056. ResEd first looks up the object's class number.  It generates a command to
  1057. run the correct CSE based on this number (see later).  This command is
  1058. passed to Wimp_StartTask.  ResEd caches the task ID of the resulting task,
  1059. so that future attempts to edit objects of this class can be passed to the
  1060. same invocation of the CSE.
  1061.  
  1062. ResEd then asks the CSE to edit the object.  It does this by sending a
  1063. message to the CSE; see later for details.  The data format used for
  1064. transferring an object to and from the CSE is identical to the data that
  1065. would represent the object within a Resource file on disk.
  1066.  
  1067. On receiving the object data, the CSE displays whatever editing window or
  1068. dialogue box is appropriate for the object.  As the user makes changes, the
  1069. CSE informs ResEd that the object has been modified by means of a message. 
  1070. ResEd uses this information to record which objects are out of date in its
  1071. own data structures.  The CSE does not send the updated object back to ResEd
  1072. (unless explicitly requested to do so by the Shell) until the user clicks on
  1073. its OK button (or closes the window, for CSEs that feature "direct
  1074. manipulation" of the object).  Transfer back to the ResEd shell is in
  1075. Resource file format using the same message protocol that was used for
  1076. loading the object.
  1077.  
  1078. Each CSE is capable of editing more than one object at a time.  To keep
  1079. track of objects in the system, the ResEd shell associates an opaque
  1080. "Document ID" with each loaded Resource file, and an opaque "Object ID" with
  1081. each object.  These IDs are quoted in all messages and together uniquely
  1082. identify an object in the message protocols between ResEd shell and CSE.
  1083.  
  1084.  
  1085. 9.1 Document Modified flag
  1086. --------------------------
  1087. CSE windows fall into two categories according to the style of interaction
  1088. they use.  Simple CSEs are merely dialogue boxes with OK and Cancel buttons. 
  1089. The object data is sent back to the shell when the user clicks OK.  Until
  1090. then, the document window's modified flag is not set.  If the user invokes a
  1091. Save operation from the shell while there are unconfirmed changes in the
  1092. dialogue box, it is the old copy of the data that gets saved.
  1093.  
  1094. More complex CSEs offer direct manipulation of an object's representation
  1095. (for example, the Window CSE).  To give the illusion of the document being
  1096. changed as the user works, the CSE sends a message to the shell when the
  1097. first change is made and the shell updates the document's title bar to show
  1098. the "modified" flag.  The modified data is not normally transmitted back to
  1099. the shell until the user closes the CSE window.  However, if the user
  1100. invokes a Save operation from the shell while there are unconfirmed changes
  1101. in the window, the shell retrieves the latest version of the object
  1102. automatically.
  1103.  
  1104. It is noted that there is inconsistency between these two categories of CSE
  1105. window.  It is hoped the user's perception that the first type is a
  1106. "dialogue box" and the second type a "window" will minimise confusion.
  1107.  
  1108.  
  1109. 9.2 Sprite relocations
  1110. ----------------------
  1111. Sprite Area Reference relocations in the Resource file format indicate which
  1112. words in the data need to be set to point to the application's private
  1113. sprite area when loaded by the ToolBox.  CSEs like the Window CSE that allow
  1114. the user to specify an indirected sprite icon should include a "Private
  1115. Sprite Pool" option button which controls where the sprite is to be found. 
  1116. If the button is on, the sprite is to be sought in the application's sprite
  1117. area before looking in the Wimp sprite pool.
  1118.  
  1119. If the button is on, the CSE sets the sprite area reference to 0; if it is
  1120. off, a NULL reference (-1) is stored. In both cases, a corresponding sprite
  1121. area reference relocation is recorded. When loading the Resource file, the
  1122. Toolbox will replace a non-NULL sprite area reference by a pointer to the
  1123. client application's sprite area, and will replace a NULL reference by 1
  1124. (meaning the Wimp Sprite pool).
  1125.  
  1126.  
  1127. 9.3 Multiple versions of classes
  1128. --------------------------------
  1129. The standard object header includes a version number for the object's class. 
  1130. This is included so that future releases of a class module can remain
  1131. compatible with old object data.  The CSE should check the version number of
  1132. each object it loads, and interpret the object data accordingly, thus
  1133. offering the same degree of backwards compatibility as the class module.  If
  1134. the object version is more recent than the CSE, the latter should issue an
  1135. error and refuse to load the object.  It is then up to the user to obtain
  1136. and install a more recent version of the CSE.
  1137.  
  1138.  
  1139. 9.4 Message Protocols
  1140. ---------------------
  1141. The interaction between the ResEd shell and the CSEs is managed by a simple
  1142. message protocol.
  1143.  
  1144. The ResEd shell starts CSEs on demand.  The first time it needs to edit an
  1145. object of a particular class, it starts the appropriate CSE as a new task. 
  1146. It records the task ID of the CSE in a table mapping class IDs to CSE task
  1147. IDs.  When the user subsequently double-clicks on another object that can be
  1148. edited by the CSE, the shell sends the editing request to the same CSE task
  1149. rather than starting a new one.  Thus CSEs must be prepared to edit more
  1150. than one object at a time.
  1151.  
  1152. A CSE can provide editing facilities for a number of classes.  This is
  1153. useful where several different classes have similar characteristics, as they
  1154. can share a common editor thus reducing memory usage, etc.
  1155.  
  1156.  
  1157. Data transfer from the shell to the CSE
  1158.  
  1159. RESED_OBJECT_LOAD (Recorded delivery)
  1160.  
  1161.  R1+0    length of block
  1162.  R1+4    task handle of sender (filled in by Wimp)
  1163.  R1+8    my_ref (filled in by Wimp)
  1164.  R1+12  your_ref (0)
  1165.  R1+16   RESED_OBJECT_LOAD
  1166.  R1+20   Flags:
  1167.                 Bit 0 set: force re-loading even if object currently open
  1168.                 All other bits reserved (should be zero)
  1169.  R1+24   Document ID: opaque handle chosen by shell
  1170.  R1+28   Object ID: opaque handle chosen by shell; unique within a document
  1171.  R1+32   Object's class
  1172.  R1+36   Object's version
  1173.  R1+40   Object's address: position of object data in sender's address space
  1174.  R1+44   Object size: length of object data in bytes
  1175.  R1+48   Object name (NUL-terminated)
  1176.  
  1177. This message is sent by the shell to a CSE to ask it to load an object for
  1178. editing.  This message is sent directly to the CSE (after the the shell has
  1179. started it, if necessary).  The message is sent recorded delivery, and the
  1180. CSE is expected to reply.  If the message bounces, the shell assumes that
  1181. the CSE has died; it posts a warning message for the user but does not
  1182. attempt to restart the CSE (to prevent possible looping).
  1183.  
  1184. The Document ID and Object ID are opaque handles that uniquely identify the
  1185. object to the CSE.  These IDs are used to identify objects in the following
  1186. messages, rather than object names.
  1187.  
  1188. On receiving this message the CSE should allocate a block of memory of
  1189. sufficient size, and then obtain the data using Wimp_TransferBlock with the
  1190. address and size information provided.  It should make a note of the
  1191. document and object IDs so that the object can be looked up in response to
  1192. future messages.  Note in particular that the CSE does NOT use the object's
  1193. name for this purpose, as this would fail when objects are renamed.
  1194.  
  1195. If the CSE receives this message when it already has the specified object
  1196. loaded, then it should merely raise its editing window to the top of the
  1197. window stack.  However, if bit 0 of the flags word is set, it should re-load
  1198. the object's data, and update its data structures and windows to reflect
  1199. this.  This is because the shell needs to flush changes after the "edit
  1200. messages" option is used - see later.
  1201.  
  1202. The object name is for the CSE's information only - it may display the name
  1203. in window titlebars, etc, but must not provide a user-interface for changing
  1204. the name.
  1205.  
  1206. When the CSE has loaded the object data, it should reply with the message
  1207. RESED_OBJECT_LOADED (even if it merely raised an existing window).  If for
  1208. any reason it was unable to load the data, it should still reply with
  1209. RESED_OBJECT_LOADED, setting flags bit 0 as described below.
  1210.  
  1211.  
  1212. RESED_OBJECT_LOADED (Normal message)
  1213.  
  1214.         R1+0    length of block
  1215.         R1+4    task handle of sender (filled in by Wimp)
  1216.         R1+8    my_ref (filled in by Wimp)
  1217.         R1+12   your_ref (copied from my_ref of RESED_OBJECT_LOAD) 
  1218.         R1+16   RESED_OBJECT_LOADED
  1219.         R1+20   Flags:
  1220.                                 Bit 0 set: load failed, error code is at R1+32
  1221.                                 All other bits reserved (should be zero)
  1222.         R1+24   Document ID: as quoted in RESED_OBJECT_LOAD
  1223.         R1+28   Object ID: as quoted in RESED_OBJECT_LOAD
  1224.  
  1225.         If flags bit 0 is set, the following additional field applies:-
  1226.         R1+32   Error code
  1227.  
  1228. When the CSE has successfully loaded an object in response to
  1229. RESED_OBJECT_LOAD, it should reply with RESED_OBJECT_LOADED with flags bit 0
  1230. clear.  This message tells the shell that the transfer was successful.
  1231.  
  1232. If the transfer was unsuccessful, the CSE should still reply with this
  1233. message, setting bit 0 of the flags word to inform the shell that the load
  1234. failed.  The error code may be used by the shell to determine how to handle
  1235. the error.  Valid error codes are:-
  1236.  
  1237. 0 - out of memory
  1238. 1 - CSE cannot handle the requested version of this object
  1239. 2 - invalid or corrupt data
  1240. 3 - non-fatal internal error
  1241. 4 - fatal internal error
  1242.  
  1243. The CSE should also display an error message to the user explaining why the
  1244. object was not loaded.  The shell will not display any error message in this
  1245. instance.
  1246.  
  1247.  
  1248. Data transfer from the CSE to the shell
  1249.  
  1250. Transfer of object data back from the CSE to the shell may be initiated by
  1251. either party.
  1252.  
  1253.  
  1254. i) Initiated by the CSE
  1255.  
  1256. RESED_OBJECT_SENDING (Recorded delivery)
  1257.  
  1258.  R1+0    length of block
  1259.  R1+4    task handle of sender (filled in by Wimp)
  1260.  R1+8    my_ref (filled in by Wimp)
  1261.  R1+12   your_ref (0)
  1262.  R1+16   RESED_OBJECT_SENDING
  1263.  R1+20   Flags:
  1264.                Bit 0 set: cannot send object, error code is at R1+32
  1265.                All other bits reserved (should be zero)
  1266.  R1+24   Document ID: opaque handle chosen by shell
  1267.  R1+28   Object ID: opaque handle chosen by shell; unique within a document
  1268.  R1+32   Address of object data in CSE's address space
  1269.  R1+36   Size of object data
  1270.  
  1271.         If flags bit 0 is set, the following additional field applies:-
  1272.  R1+40   Error code
  1273.  
  1274.  
  1275. When the user clicks the OK button or the Close icon of a CSE window, the
  1276. CSE needs to transmit the object back to the shell (if it has changed).  The
  1277. CSE sends RESED_OBJECT_SENDING to the ResEd shell task that owns the object,
  1278. quoting the correct document ID and object ID, and the address and size of
  1279. the object data.  Flags bit 0 of the message shall be clear.
  1280.  
  1281. The shell determines which object is being updated.  It allocates a buffer
  1282. of the size quoted in the RESED_OBJECT_SENDING message, and then transfers
  1283. the data with Wimp_TransferBlock.  If this is successful, it then
  1284. de-allocates the old data associated with the object and stores the
  1285. newly-received data instead.  It clears its internal modified flag for the
  1286. object and sets the modified flag on the document, placing a "*" in the
  1287. titlebar.
  1288.  
  1289. The shell then replies to the RESED_OBJECT_SENDING message with
  1290. RESED_OBJECT_LOADED so that the CSE is aware that the transfer was
  1291. successful.  The CSE can now clean up its data structures, close its window
  1292. etc.  If the CSE does not receive a reply to the message, it should just
  1293. deallocate any temporary storage that it allocated for the transaction.
  1294.  
  1295. If the shell is unable to load the object - for example, if it cannot
  1296. allocate memory - it replies with RESED_OBJECT_LOADED, setting flags bit 0
  1297. and inserting a suitable error code into the reply.  The shell then displays
  1298. the error message.  This will typically say "There was not enough memory for
  1299. this operation - please free some memory and try again".  On receipt of
  1300. RESED_OBJECT_LOADED with the error indication, the CSE tidies up any
  1301. temporary store allocated for the transaction, but does not close the
  1302. object.
  1303.  
  1304.  
  1305. ii) Initiated by the shell
  1306.  
  1307. When the shell needs to save the document (or part thereof) it must reclaim
  1308. the latest version of any objects that are currently being modified in CSEs. 
  1309. This is only done for objects which are known to have been modified (ie
  1310. RESED_OBJECT_MODIFIED has been received), or for certain "force-loaded"
  1311. objects (see section 5.2.3). The shell requests the updated object using the
  1312. following message:-
  1313.  
  1314. RESED_OBJECT_SEND (Recorded delivery)
  1315.  
  1316.  R1+0    length of block
  1317.  R1+4    task handle of sender (filled in by Wimp)
  1318.  R1+8    my_ref (filled in by Wimp)
  1319.  R1+12   your_ref (0)
  1320.  R1+16   RESED_OBJECT_SEND
  1321.  R1+20   Flags:
  1322.                Bit 0 set: delete after successful send (see section 5.2.3)
  1323.                All other bits reserved (should be zero)
  1324.  R1+24   Document ID: opaque handle chosen by shell
  1325.  R1+28   Object ID: opaque handle chosen by shell; unique within a document
  1326.  
  1327. The CSE should reply to this message using RESED_OBJECT_SENDING sent
  1328. recorded delivery, passing the address and size of the object data back to
  1329. the shell.  The transfer then proceeds as detailed in 5.1.1. The shell will
  1330. reply with RESED_OBJECT_LOADED sent as a normal message (not recorded
  1331. delivery).  The shell should clear it's modified flag for the object, and
  1332. set the modified flag for the document.  When the CSE receives the
  1333. RESED_OBJECT_LOADED message, it should clear its internal "modified" flags
  1334. for the object, and deallocate any temporary storage that was used for the
  1335. transfer. If bit 0 was set in the original RESED_OBJECT_SEND message, the
  1336. object should now be deleted from the CSE; if not, no further action is
  1337. necessary (and the window for the object should be left open).
  1338.  
  1339. There are several points at which the above transaction could fail.
  1340.  
  1341. a) If the CSE is unable to honour the shell's RESED_OBJECT_SEND
  1342. message, it should reply with RESED_OBJECT_SENDING (sent as a normal
  1343. message, not recorded delivery).  It should set flags bit 0 of this message,
  1344. and insert an error code.  The CSE should also display an error message to
  1345. the user.  The error code may be used by the shell to determine how to
  1346. handle the error.  Valid error codes are:-
  1347.  
  1348. 0 - out of memory
  1349. 1 - object is unknown
  1350. 3 - non-fatal internal error
  1351. 4 - fatal internal error
  1352.  
  1353. On receipt of this message, the shell cancels the operation that caused the
  1354. object recovery to take place (save, export messages, etc).
  1355.  
  1356. b) If the shell is unable to honour the CSE's RESED_OBJECT_SENDING message,
  1357. it should reply with RESED_OBJECT_LOADED setting flags bit 0 and inserting
  1358. an error code as described in section 5.1.  The shell should then display an
  1359. error message to the user and cancel the transaction.  The CSE should
  1360. deallocate any temporary storage that was used for the transfer.  The CSE
  1361. may use the error code to determine what went wrong, but it should not
  1362. display an error message because the shell has already done so.
  1363.  
  1364. c) If the shell's RESED_OBJECT_SEND message bounces, it is probably because
  1365. the CSE has died.  It should move on to the next object requiring recovery;
  1366. tidying up after the dead CSE is done in response to the Wimp_TaskCloseDown
  1367. message.
  1368.  
  1369. d) If the CSE's RESED_OBJECT_SENDING message bounces, it should just
  1370. deallocate any temporary storage that it allocated for the transaction.
  1371.  
  1372.  
  1373. Note: Dialogue-box style CSEs that do not send the message
  1374. RESED_OBJECT_MODIFIED will only receive RESED_OBJECT_SEND under the
  1375. circumstances described in section 5.2.3 below.
  1376.  
  1377.  
  1378. iii) Importing revised messages
  1379.  
  1380. If an object's messages have been changed as a result of importing a revised
  1381. messages file, then that object must be processed by its CSE to ensure that
  1382. all associated length fields are consistent with the new messages.
  1383.  
  1384. For example, suppose a window's 'helpmessage' field has been changed from
  1385. "Hello" to "Welcome to my world"; the associated length field 'maxhelp' must
  1386. now be at least 20, whereas previously 6 bytes were sufficient.
  1387.  
  1388. The protocol associated with this process is as follows:
  1389.  
  1390. The Shell sends RESED_OBJECT_LOAD to the CSE with flag bit 0 set (force
  1391. load).
  1392.  
  1393. If the CSE already holds a copy of the object, it replaces that copy by the
  1394. new version and refreshes the associated editing window or main dialogue
  1395. box, and refreshes or hides any subsidiary dialogue boxes.
  1396.  
  1397. If the CSE does not already hold a copy of the object, it loads the object
  1398. but does not display it (ie no editing window or main dialogue box is
  1399. opened).
  1400.  
  1401. Note that any length fields are modified to be consistent with their
  1402. associated message fields as part of this (re)loading process.
  1403.  
  1404. The CSE replies with a RESED_OBJECT_LOADED message.
  1405.  
  1406. If the object concerned was, in any case, being edited by the CSE at the
  1407. time of message import, no further action is necessary other than for the
  1408. shell to note that its copy of the object may now be out-of-date.
  1409.  
  1410. If, on the other hand, the object was force-loaded into the CSE just to
  1411. check its length fields, it must now be immediately retrieved - so the shell
  1412. sends RESED_OBJECT_SEND to the CSE with flag bit 0 set (delete after
  1413. sending).
  1414.  
  1415. The CSE replies with a RESED_OBJECT_SENDING message.  It should set the
  1416. your_ref field of this message from the my_ref field of the
  1417. RESED_OBJECT_SEND message which was just received.
  1418.  
  1419. The shell recovers the revised object data, and replies with a
  1420. RESED_OBJECT_LOADED message.
  1421.  
  1422. The CSE deletes the object, and sends a RESED_OBJECT_CLOSED message to the
  1423. shell.
  1424.  
  1425. Upon receipt of this message the shell marks the object as not being edited
  1426. and the protocol is complete.
  1427.  
  1428.  
  1429. Object status messages
  1430.  
  1431. RESED_OBJECT_RENAMED (Normal message)
  1432.  
  1433.         R1+0    length of block
  1434.         R1+4    task handle of sender (filled in by Wimp)
  1435.         R1+8    my_ref (filled in by Wimp)
  1436.         R1+12   your_ref (0)
  1437.         R1+16   RESED_OBJECT_RENAMED
  1438.         R1+20   Flags: all bits reserved (should be zero)
  1439.         R1+24   Document ID: as quoted in RESED_OBJECT_LOAD
  1440.         R1+28   Object ID: as quoted in RESED_OBJECT_LOAD
  1441.         R1+32   New name: NUL-terminated string
  1442.  
  1443. Sent to the CSE by the shell when the user renames an object.  If the CSE is
  1444. holding state for this object it should update its record of the object's
  1445. name, and redraw titlebars etc as necessary.  Despite the presence of this
  1446. message, the CSE should not provide a user-interface to renaming objects, as
  1447. this is handled centrally by the shell.
  1448.  
  1449.  
  1450. RESED_OBJECT_DELETED (Normal message)
  1451.  
  1452.         R1+0    length of block
  1453.         R1+4    task handle of sender (filled in by Wimp)
  1454.         R1+8    my_ref (filled in by Wimp)
  1455.         R1+12   your_ref (0)
  1456.         R1+16   RESED_OBJECT_DELETED
  1457.         R1+20   Flags: all bits reserved (should be zero)
  1458.         R1+24   Document ID: as quoted in RESED_OBJECT_LOAD
  1459.         R1+28   Object ID: as quoted in RESED_OBJECT_LOAD
  1460.  
  1461. Sent to the CSE by the shell when the user deletes an object.  If the CSE is
  1462. holding state for this object it must delete any windows, de-allocate
  1463. memory, etc.  It should do this silently, without asking about unsaved
  1464. changes, as this is the responsibility of the shell.
  1465.  
  1466. This message is also sent when the user moves a resource from one document
  1467. to another, or when the document containing the resource is closed.  As far
  1468. as the CSE is concerned, this is indistinguishable from deletion.
  1469.  
  1470. The given (Document ID, Object ID) pair will not be re-used.
  1471.  
  1472.  
  1473. RESED_OBJECT_MODIFIED (Normal message)
  1474.  
  1475.         R1+0    length of block
  1476.         R1+4    task handle of sender (filled in by Wimp)
  1477.         R1+8    my_ref (filled in by Wimp)
  1478.         R1+12   your_ref (0)
  1479.         R1+16   RESED_OBJECT_MODIFIED
  1480.         R1+20   Flags: all bits reserved (should be zero)
  1481.         R1+24   Document ID: as quoted in RESED_OBJECT_LOAD
  1482.         R1+28   Object ID: as quoted in RESED_OBJECT_LOAD
  1483.  
  1484. This message allows the shell to track the state of objects when they are
  1485. altered in a CSE.  The shell uses this information to decide whether it
  1486. needs to recover the object data when the document (or the object's
  1487. messages) is saved.  The message is sent from the CSE to the shell when the
  1488. user modifies the CSE's copy of an object.  The shell records this fact in
  1489. its data structure describing the object, and also sets the modified flag
  1490. for the whole document.  The CSE should only send this message when the
  1491. object's state goes from "unmodified" to "modified".
  1492.  
  1493. Note: CSEs which have "dialogue box-like" behaviour should never send this
  1494. message.  The transfer of object data from such CSEs is always initiated by
  1495. the user clicking OK, and the document's "modified" flag is not set until
  1496. this is done.
  1497.  
  1498.  
  1499. RESED_OBJECT_CLOSED (Normal message)
  1500.  
  1501.         R1+0    length of block
  1502.         R1+4    task handle of sender (filled in by Wimp)
  1503.         R1+8    my_ref (filled in by Wimp)
  1504.         R1+12   your_ref (0)
  1505.         R1+16   RESED_OBJECT_CLOSED
  1506.         R1+20   Flags: all bits reserved (should be zero)
  1507.         R1+24   Document ID: as quoted in RESED_OBJECT_LOAD
  1508.         R1+28   Object ID: as quoted in RESED_OBJECT_LOAD
  1509.  
  1510. Sent from the CSE to the shell when the object's editing window is closed. 
  1511. This also happens when the user clicks SELECT on the "Cancel" button or
  1512. presses ESCAPE, and also when the user SELECT-clicks on the "OK" button.  In
  1513. the latter case the message should be sent in reply to the
  1514. RESED_OBJECT_LOADED message sent by the shell.
  1515.  
  1516. The CSE should not send this message in response to RESED_OBJECT_DELETED, as
  1517. the shell expects the window to be closed in response to that message.
  1518.  
  1519.  
  1520. Other messages
  1521.  
  1522. RESED_SPRITES_CHANGED (Broadcast)
  1523.  
  1524.         R1+0    length of block
  1525.         R1+4    task handle of sender (filled in by Wimp)
  1526.         R1+8    my_ref (filled in by Wimp)
  1527.         R1+12   your_ref (0)
  1528.         R1+16   RESED_SPRITES_CHANGED
  1529.         R1+20   Flags: all bits reserved (should be zero)
  1530.  
  1531. Broadcast by the Shell when the user has loaded a Sprites file by dragging
  1532. it to the iconbar icon.  CSEs that are displaying user-specified sprites
  1533. should redraw their windows on receipt of this message.
  1534.  
  1535.  
  1536. RESED_OBJECT_NAME_REQUEST (Normal message)
  1537.  
  1538.         R1+0    length of block
  1539.         R1+4    task handle of sender (filled in by Wimp)
  1540.         R1+8    my_ref (filled in by Wimp)
  1541.         R1+12   your_ref (copied from my_ref of DataSave message)
  1542.         R1+16   RESED_OBJECT_NAME_REQUEST
  1543.         R1+20   Flags: all bits reserved (should be zero)
  1544.         R1+24   Document ID of requesting object
  1545.         R1+28   Object ID of requesting object
  1546.         R1+32   Window handle of destination window
  1547.         R1+36   Icon handle in destination window (-1 for none)
  1548.  
  1549.  
  1550. RESED_OBJECT_NAME (Normal message)
  1551.  
  1552.  R1+0    length of block
  1553.  R1+4    task handle of sender (filled in by Wimp)
  1554.  R1+8    my_ref (filled in by Wimp)
  1555.  R1+12   your_ref (copied from my_ref of RESED_OBJECT_NAME_REQUEST)
  1556.  R1+16   RESED_OBJECT_NAME
  1557.  R1+20   Flags: 
  1558.                     Bit 0 set: request refused
  1559.                     All other bits reserved (should be zero)
  1560.  R1+24   Document ID of requesting object                (PRESERVED)
  1561.  R1+28   Object ID of requesting object                          (PRESERVED)
  1562.  R1+32   Window handle of destination window                     (PRESERVED)
  1563.  R1+36   Icon handle in destination window (-1 for none)         (PRESERVED)
  1564.  R1+40   Class of dragged object
  1565.  R1+44   Object name: NUL-terminated string
  1566.  
  1567. Many CSE dialogue boxes offer a writable icon for the input of an object
  1568. name (for example the name of an object to open when an action button is
  1569. pressed).  The user can fill these in by dragging the object's icon from the
  1570. shell's document display window into the writable icon (or onto an
  1571. associated option icon if the writable is faded).
  1572.  
  1573. When such a drag is initiated by the user, the shell does not know that the
  1574. destination is such a field, so the shell sends a DataSave message as
  1575. normal.  If the CSE spots that the drag was to an object name writable
  1576. field, it replies with RESED_OBJECT_NAME_REQUEST rather than the usual
  1577. DataSaveAck or RamFetch messages.  When the shell receives this message, it
  1578. replies with RESED_OBJECT_NAME.  It then considers the DataSave operation
  1579. complete.
  1580.  
  1581. The shell will reply with flags bit 0 set after displaying an error message
  1582. under the following circumstances:-
  1583.  
  1584. - the document ID quoted in RESED_OBJECT_NAME_REQUEST is different from that
  1585. of the document the object was dragged from - more than one object was
  1586. dragged
  1587.  
  1588. In this case the shell will abort the DataSave operation, and the CSE should
  1589. leave the writable field unaltered.
  1590.  
  1591. The CSE may check the class field of the reply to ensure that the dragged
  1592. object was of a suitable type.  It may also check the Object ID field to
  1593. guard against self-referential links.
  1594.  
  1595. The "Document ID", "Object ID", "Window handle" and "Icon handle" fields are
  1596. for the CSE's use - the shell must preserve the contents of these fields
  1597. when building its reply.
  1598.  
  1599.  
  1600. RESED_KEYCUT_DETAILS (Normal message)
  1601.  
  1602.  R1+0    length of block
  1603.  R1+4    task handle of sender (filled in by Wimp)
  1604.  R1+8    my_ref (filled in by Wimp)
  1605.  R1+12   your_ref (0)
  1606.  R1+16   RESED_KEYCUT_DETAILS
  1607.  R1+20   Flags: 
  1608.                 Bit 0 set: this keyboard shortcut raises an event
  1609.                 Bit 1 set: this keyboard shortcut shows an object
  1610.                 Bit 2 set: any object shown by this keyboard shortcut is shown 
  1611.                            transiently
  1612.                 All other bits reserved (should be zero)
  1613.  R1+24   Task id of shell
  1614.  R1+28   Window handle of destination windowR1+32   Key code
  1615.  R1+36   Event code (valid only if flag bit 0 set)
  1616.  R1+40   Key name: NUL-terminated string
  1617.          Object name: NUL-terminated string - required only if flag bit 1 set
  1618.  
  1619. This specialised message is sent from the Window CSE to the Menu CSE after
  1620. the user has dragged a keyboard shortcut entry from the Window editor's
  1621. Keyboard shortcuts scrolling pane to the Menu editor's Menu entry properties
  1622. dialogue box (see the relevant Functional Specifications for more details of
  1623. these windows). The purpose of the message is to transmit details of a
  1624. keyboard shortcut from the Window CSE to the Menu CSE, so that it is easy to
  1625. make sure that the actions associated with a keypress on a window are the
  1626. same as those associated with a menu choice.
  1627.  
  1628.  
  1629. 9.5 CSE start-up
  1630.  
  1631. The CSEs are stored inside a subdirectory of the ResEd application. Each
  1632. contains a file called !Config which the shell uses to determine which CSEs
  1633. offer editing facilities for which classes. 
  1634.  
  1635. A CSE is started automatically by the shell the first time it is required. 
  1636. The CSE is started by calling Wimp_StartTask, passing as a parameter the
  1637. task ID of the shell expressed as a decimal numeric string.
  1638.  
  1639. If Wimp_StartTask returns 0, it was not possible to start the task, possibly
  1640. because there is insufficient free memory.  In this case the shell issues a
  1641. warning to the user and aborts the operation.
  1642.  
  1643. Otherwise the value returned by Wimp_StartTask is the task ID of the
  1644. newly-started CSE.  The shell immediately sends RESED_OBJECT_LOAD to the
  1645. task and remembers the task ID for future editing requests on this class (or
  1646. any of the other classes that the CSE can handle).
  1647.  
  1648. When a CSE is executed, it initially has very little work to do.  It first
  1649. makes a note of the task ID of its parent shell (passed in on the command
  1650. line).  It will need this information to ensure that it only responds to
  1651. messages from its parent task.  Next it calls Wimp_Initialise to register
  1652. itself as a Wimp task.  It next performs any initialisation that it needs
  1653. for its own internal data structures, and then calls Wimp_Poll.  At this
  1654. point the ResEd shell regains control and is told the task ID of the CSE.
  1655.  
  1656. CSEs should use an OS variable of the form <CSE{class }$Dir> to communicate
  1657. their application directory name from the !Run file into the application,
  1658. and the application should expand the value and store it before first
  1659. calling Wimp_Poll.  It should use this expanded value rather than the
  1660. variable itself when referring to the contents of its application directory. 
  1661. This precaution is needed to ensure that CSEs from two different versions of
  1662. ResEd can co-exist.
  1663.  
  1664.  
  1665. 9.6 Multiple-class CSEs
  1666.  
  1667. To avoid needless code duplication, CSEs may provide editing facilities for
  1668. more than one class.  The shell uses the information in the CSE's !Config
  1669. file (see Implementation Notes) to determine which classes it can edit.
  1670.  
  1671.  
  1672. 9.7 CSE death
  1673.  
  1674. When the shell receives the broadcast message Wimp_TaskCloseDown, it checks
  1675. the task ID against all the CSE task IDs it has cached.  If the ID matches
  1676. any of these, then one of the CSEs has unexpectedly died.
  1677.  
  1678. The shell removes references to this task ID from its lookup table and
  1679. resets its private "being edited" flag on any objects that were currently
  1680. being edited by that task.  Subsequent attempts to edit objects of the class
  1681. handled by the dead CSE will result in the task being restarted.  Another
  1682. circumstance when the shell detects and act on CSE death is when an attempt
  1683. to send a message to the CSE returns an error.
  1684.  
  1685.  
  1686. 9.8 Shell death
  1687.  
  1688. CSEs should check any Wimp_TaskCloseDown messages they receive.  If the task
  1689. that exited was their parent, they should immediately exit silently.  This
  1690. is the only mechanism to ensure that CSEs do not outlive the shell.
  1691.  
  1692.  
  1693. 9.9 Drag and drop
  1694.  
  1695. Drag-and-drop within a particular CSE can be provided as the author of the
  1696. CSE sees fit.  The only drag-and-drop interaction supported between the
  1697. shell and the CSE is the dragging of an object from the document window into
  1698. a CSE dialogue box in order to enter the object's name in a writable field. 
  1699. The messages RESED_OBJECT_NAME_REQUEST and RESED_OBJECT_NAME should be used,
  1700. as described in an earlier section.
  1701.  
  1702.  
  1703. 9.10 Standard message protocols
  1704.  
  1705. The ResEd shell and its CSEs respond to the following standard message
  1706. protocols as documented in the PRM:-
  1707.  
  1708.   - Quit protocol
  1709.   - Desktop Save protocol
  1710.   - Shutdown protocol
  1711.   - Interactive Help protocol
  1712.  
  1713.  
  1714. 9.11  Implementation notes
  1715.  
  1716. i)  Filetypes and message numbers
  1717.  
  1718. The filetype registered for a Resource file is &fae.
  1719.  
  1720. Registered message numbers are:
  1721.  
  1722.     &83340    MESSAGE_RESED_OBJECT_LOAD
  1723.     &83341    MESSAGE_RESED_OBJECT_LOADED
  1724.     &83342    MESSAGE_RESED_OBJECT_SEND
  1725.     &83343    MESSAGE_RESED_OBJECT_SENDING
  1726.     &83344    MESSAGE_RESED_OBJECT_RENAMED
  1727.     &83345    MESSAGE_RESED_OBJECT_DELETED
  1728.     &83346    MESSAGE_RESED_OBJECT_MODIFIED
  1729.     &83347    MESSAGE_RESED_OBJECT_CLOSED
  1730.     &83348    MESSAGE_RESED_SPRITES_CHANGED
  1731.     &83349    MESSAGE_RESED_OBJECT_NAME_REQUEST
  1732.     &8334a    MESSAGE_RESED_OBJECT_NAME
  1733.     &8334b    MESSAGE_RESED_KEYCUT_DETAILS
  1734.  
  1735.  
  1736. ii) Directory structure
  1737.  
  1738. The structure of !ResEd's directory hierarchy is as follows:-
  1739.  
  1740. !ResEd                                Top-level application run by user
  1741.        !Boot                          !Boot file for the shell
  1742.        !Help                          !Help file for the shell
  1743.        !Run                           !Run file for the shell
  1744.        !RunImage                      !RunImage file for the shell
  1745.        Templates                      Wimp templates for the shell
  1746.        Messages                       Messages and interactive help for 
  1747.                                       the shell
  1748.        !Sprites, !Sprites22           Resource filetype and application 
  1749.                                       icon sprites
  1750.        Sprites, Sprites22             Sprites used by the shell
  1751.        CSE                            Directory containing CSEs
  1752.             !Menu                     CSE for class Menu
  1753.                    !Help              its !Help file
  1754.                    !Run               its !Run file
  1755.                    !RunImage          its !RunImage file
  1756.                    !Config            CSE description file - see below
  1757.                    !Palette           Palette entries for the shell - see below
  1758.                    !Icons, !Icons22   Sprites file containing class 
  1759.                                       icon(s) - see below
  1760.                    Templates          Wimp templates for the CSE
  1761.                    Sprites            its sprites (if any)
  1762.                    Messages           its messages and interactive help
  1763.                    Palette            Palette entries for its palette (if any)
  1764.              !Window                  CSE for class Window
  1765.                    <as for !Menu>
  1766.              !Misc                    CSE for other classes
  1767.                    <as for !Menu>
  1768.  
  1769. !ResEd.Sprites contains all the sprites used internally by the shell. It
  1770. does not contain the sprites to be used for the various object's icons;
  1771. these are loaded from the individual CSEs.
  1772.  
  1773. The !ResEd.CSE directory contains all the CSE applications.  The names
  1774. assigned to these are arbitrary.  CSE apps contain three special files used
  1775. by the Shell to determine information about the CSE before it has been
  1776. started.  The shell walks the CSE directory and reads the following files
  1777. from each:-
  1778.  
  1779. !Config: a text file describing this CSE.  The file contains one line for
  1780. each class handled by the CSE, containing three comma-separated fields: the
  1781. hexadecimal class ID, the human-readable class name, and the sprite name to
  1782. be used when looking up the class' icon sprite.
  1783.  
  1784. eg   0x828c0,Menu,obj_menu
  1785.  
  1786. !Icons: sprites file containing the icon sprites for the class(es) edited by
  1787. the CSE.  The shell loads this with *iconsprites.
  1788.  
  1789. !Palette: a Resource file containing prototype objects for the classes
  1790. edited by the CSE.  The shell merges the !Palette files from all the CSEs to
  1791. create its palette.
  1792.  
  1793.  
  1794. 9.12 General behaviour and standards
  1795. ------------------------------------
  1796. ResEd's user interface adheres to the recommendations in the second edition
  1797. of the RISC OS Style Guide.  Also, its editing capabilities are designed to
  1798. encourage the creation of Style Guide compliant applications.
  1799.  
  1800. ResEd's selection model and drag-and-drop system operate according to the
  1801. following Support Group application notes:-
  1802.  
  1803.   The RISC OS Selection Model and Clipboard
  1804.   The RISC OS Drag and Drop System
  1805.  
  1806.  In particular (and in addition) the following general dialogue box ("dbox")
  1807. behaviour is supported wherever possible by both the Shell and all CSEs:
  1808.  
  1809. Clicking ADJUST on the default action button (eg on "OK") applies a dbox but
  1810. does not remove it from the screen.
  1811.  
  1812. Clicking ADJUST on the cancel action button (eg on "Cancel") resets the
  1813. state of the dbox to that which it had when it was last opened (or when
  1814. ADJUST was last clicked on its default action button).
  1815.  
  1816. Wherever option or radio buttons control the relevance of other icons in the
  1817. dbox, these icons are unfaded only when it is sensible to use them; for
  1818. example, the writable into which Help Text is written is unfaded only when
  1819. the corresponding option button is ticked.
  1820.  
  1821.  When a dbox has the input focus:
  1822.  
  1823. TAB/SHIFT-TAB or DOWN/UP CURSOR keys will cycle the caret through any
  1824. unfaded writables.
  1825.  
  1826. Pressing RETURN has the same effect as clicking SELECT on the default action
  1827. button.
  1828.  
  1829. Pressing SHIFT-RETURN has the same effect as clicking ADJUST on the default
  1830. action button.
  1831.  
  1832. Pressing ESCAPE has the same effect as clicking SELECT on the cancel action
  1833. button.
  1834.  
  1835. Pressing SHIFT-ESCAPE has the same effect as clicking ADJUST on the cancel
  1836. action button (but note that the Wimp does not allow this for transient
  1837. dialogue boxes).
  1838.  
  1839. Clicking in any dbox gives it input focus (even if it has no writables).
  1840.  
  1841. When a dbox is first opened, input focus is given to it and the caret is
  1842. placed in the first unfaded writable, if any.
  1843.  
  1844. When the state of an option or radio button is changed in such a way that
  1845. some corresponding writable containing the caret is faded, then the caret is
  1846. removed from that faded icon and placed in the next unfaded writable, if any.
  1847.  
  1848. If an option or radio button associated with a writable is switched on, then
  1849. the caret is immediately placed in that writable.
  1850.  
  1851. When a dialogue box is closed, the input focus is returned to its "parent" 
  1852. window.
  1853.  
  1854. Numeric values can normally be entered in either hexadecimal or decimal: the 
  1855. former is indicated by an initial "&". Many values, such as event codes and 
  1856. component ids, are displayed in hexadecimal, this being indicated once more 
  1857. by an initial "&".
  1858.  
  1859. Any message or string field inside an object template contains either a
  1860. string or a NULL value. In some cases there is no difference in behaviour
  1861. between a NULL value and an empty string, and in such situations ResEd will
  1862. always save a NULL value (rather than an empty string) since this occupies
  1863. less space in the Resource File. When there *is* a difference, the CSE will
  1864. provide an option or radio button whose state determines whether the field
  1865. is set to an explicit string value or to NULL.
  1866.  
  1867. Many object templates include message or string fields which have length
  1868. fields associated with them. For example, a window object template has a
  1869. "helpmessage" field with an associated "maxhelp" field. In such cases, the
  1870. length field determines the size of buffer allocated for the text field
  1871. whenever an object is created from the template; in other words, it
  1872. determines the size of the longest string that can ever be assigned to the
  1873. text field of that object at run-time. Continuing the example, if "maxhelp"
  1874. is set to 20, then any string set by the Window_SetHelpMessage method must
  1875. always be at most 19 characters long (one byte must be allowed for the NULL
  1876. terminator).
  1877.  
  1878. In many cases, the client application will never wish to change the text
  1879. field at run-time, and so the buffer length should be chosen so that the
  1880. fixed string just fits. To make this easy to do, each CSE allows the user to
  1881. specify "*" as the value of a length field - and will then set the
  1882. corresponding field of the object template according to the length of the
  1883. associated text field value. The precise rules are as follows:
  1884.  
  1885. Let N be the value of the length field inside the object template, 
  1886. and let L, the length of the corresponding text field, be defined as follows:
  1887.  
  1888. If the text field is NULL, L = 0.
  1889. If the text field contains the string s, then L = strlen(s) + 1.
  1890.  
  1891. (Note that it is possible to have a NULL text field with a non-zero length 
  1892. field.)
  1893.  
  1894. During the editing process, the value of N can be an integer >= 0 or can be 
  1895. the special value "*". 
  1896.  
  1897. But "*" cannot be represented inside the object template itself, and so 
  1898. translation has to take place when the object is loaded into the CSE, and when 
  1899. it is returned to the shell.
  1900.  
  1901. When an object is loaded into a CSE for editing, N is set to "*" if and only 
  1902. if N = L.
  1903.  
  1904. When an object is returned to the shell, any "*" value is replaced by 0 (if
  1905. the text field is NULL) or by strlen(s) + 1 (if the text field contains a
  1906. non-NULL value s).
  1907.  
  1908. The loading process also makes sure that every length field is at least
  1909. large enough to contain its corresponding string: if N < L, then N is set to
  1910. "*". (This is how CSEs restore consistency after message import.)
  1911.  
  1912. When editing a length field in a dialogue box, the user may enter any
  1913. positive integer or an  asterisk. When he applies the dbox (by clicking on
  1914. OK) the CSE again ensures that the field is large enough for the
  1915. corresponding string: any numerical value entered by the user that is too
  1916. small is replaced by the minimum value necessary (ie strlen(s) + 1).
  1917.  
  1918. Other user interface behaviour common to all components of ResEd includes:
  1919.  
  1920. Pressing ESCAPE will cancel any user drag or "lassoo" operation, and will
  1921. hide any menu on display.
  1922.  
  1923. Keyboard shortcuts are inoperative during a drag or lassoo interaction, and
  1924. will cancel any menu on display.
  1925.  
  1926. Pressing any one of the four cursor keys during a drag or lassoo interaction
  1927. will "nudge" the pointer in the corresponding direction by 4 OS units.
  1928.  
  1929. All coordinates (position and size) are forced to be exact multiples of 4 OS
  1930. units.
  1931.  
  1932. "Auto-scrolling" is supported for all drag and lassoo operations. If the
  1933. mouse pointer remains close to the edge of a window for long enough, the
  1934. pointer changes shape and the window will scroll in  that direction; the
  1935. speed of scrolling increases as the pointer gets closer to the edge of the
  1936. window. This means that the user must drag decisively in order to move an
  1937. object from one window to another.
  1938.  
  1939. Clicking on an adjuster arrow changes the associated numerical value by a
  1940. small amount (usually 1); if SHIFT is held down at the same time, the
  1941. associated value is changed by a larger amount (usually 10).